home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir31
/
guspeak.zip
/
PARSE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-29
|
13KB
|
619 lines
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <gf1proto.h>
#include <ultraerr.h>
#include <dos.h>
#define MAX_LENGTH 128
static FILE *In_file;
static FILE *Out_file;
static int no_ultra = 0;
static int Char, Char1, Char2, Char3;
static void load_phonemes(void);
int makeupper(int character);
int new_char(void);
void xlate_file(void);
void have_dollars(void);
void have_special(void );
void have_number(void);
void have_letter(void);
void abbrev(char buff[]);
void outstring(char *string);
void say_ordinal(long int value);
void say_cardinal(long int value);
void say_ascii(int character);
void spell_word(char *word);
void xlate_word(char *buf);
void outchar(int chr);
/*
** main(argc, argv)
** int argc;
** char *argv[];
**
** This is the main program. It takes up to two file names (input
** and output) and translates the input file to phoneme codes
** (see ENGLISH.C) on the output file.
*/
int verbose = 0;
int debug = 0;
void main(int argc, char *argv[])
{
int i=1;
/* process switches */
while (argv[i][0] == '-') {
switch (argv[i++][1]) {
case 'd': debug = 1; break;
case 'v': verbose = 1; break;
default :
fputs("Usage: PHONEME [-v -d] [infile [outfile]]\n", stderr);
fputs(" -v verbose mode (print phonemes)\n", stderr);
fputs(" -d debug mode speak each phoneme\n", stderr);
exit(0);
}
}
--i;
if ((argc-i) > 1)
{
In_file = fopen(argv[1+i], "r");
if (In_file == 0)
{
fputs("Error: Cannot open input file.\n", stderr);
fputs("Usage: PHONEME [infile [outfile]]\n", stderr);
exit(0);
}
}
else
In_file = stdin;
if (argc-i > 2)
{
Out_file = fopen(argv[2+i], "w");
if (Out_file == 0)
{
fputs("Error: Cannot create output file.\n", stderr);
fputs("Usage: PHONEME [-d-v] [infile [outfile]]\n", stderr);
exit(0);
}
}
else
Out_file = stdout;
load_phonemes();
if (argc-i == 1) {
fputs("Enter english text:\n", stderr);
}
xlate_file();
UltraClose();
}
/* an array of all phonemes */
static char *phoneme_name[] = {
"IY", "EY", "AE", "AO", "UH",
"ER", "AH", "AW", "IH", "EH",
"AA", "OW", "UW", "AX", "AY",
"OY", "YU", "p", "t", "k",
"f", "TH", "s", "SH", "HH",
"n", "l", "y", "CH", "WH",
"b", "d", "g", "v", "DH",
"z", "ZH", "m", "NG", "w",
"r", "j"
};
/* this stucture holds that gravis start and end address for each phoneme */
/* phonemes that start with upperchase char are two characters long */
static struct w_table {
unsigned long start;
unsigned long end;
} p_tab[sizeof(phoneme_name)/sizeof(char *)];
/* return index of phonemes s in phoneme_name array.
** return -1 if not found
*/
int find_phon_index(char *s)
{
int len;
int i;
/* if two character search */
if (isupper(*s))
len = 2;
else
len = 1;
for (i = 0;i < sizeof(phoneme_name)/sizeof(char *); i++) {
if (strncmp(s,phoneme_name[i], len) == 0)
return(i);
}
return(-1);
}
/* break the string s up into sound samples and play them */
void gus_speak(char *s)
{
int i;
char *p = s;
/* while there are phonemes */
while(*p) {
/* if pause then wait .1 sec */
if (*p == ' ') {
delay(100);
/* bump pointer to start of next phoneme */
p++;
continue;
}
i = find_phon_index(p);
if (i < 0) {
printf("\n[%s] phoneme not found in voice table ", p);
p++;
continue;
}
/* play the phoneme sound sound */
UltraStartVoice(1, p_tab[i].start, p_tab[i].start, p_tab[i].end, 4);
/* wait for sound to stop */
while(!UltraVoiceStopped(1));
/* bumb pointer to start of next phoneme */
if isupper(*(p++))
p++;
}
}
void outstring(char *string)
{
/* if ultrasound is instaled then speak the string */
if (!no_ultra)
gus_speak(string);
if (!verbose)
return;
/* print the string */
while (*string != '\0')
outchar(*string++);
}
void outchar(int chr)
{
fputc(chr,Out_file);
}
int makeupper(int character)
{
if (islower(character))
return toupper(character);
else
return character;
}
int new_char(void)
{
/*
If the cache is full of newline, time to prime the look-ahead
again. If an EOF is found, fill the remainder of the queue with
EOF's.
*/
if (Char == '\n' && Char1 == '\n' && Char2 == '\n' && Char3 == '\n')
{ /* prime the pump again */
Char = getc(In_file);
if (Char == EOF)
{
Char1 = EOF;
Char2 = EOF;
Char3 = EOF;
return Char;
}
if (Char == '\n')
return Char;
Char1 = getc(In_file);
if (Char1 == EOF)
{
Char2 = EOF;
Char3 = EOF;
return Char;
}
if (Char1 == '\n')
return Char;
Char2 = getc(In_file);
if (Char2 == EOF)
{
Char3 = EOF;
return Char;
}
if (Char2 == '\n')
return Char;
Char3 = getc(In_file);
}
else
{
/*
Buffer not full of newline, shuffle the characters and
either get a new one or propagate a newline or EOF.
*/
Char = Char1;
Char1 = Char2;
Char2 = Char3;
if (Char3 != '\n' && Char3 != EOF)
Char3 = getc(In_file);
}
return Char;
}
/*
** xlate_file()
**
** This is the input file translator. It sets up the first character
** and uses it to determine what kind of text follows.
*/
void xlate_file(void)
{
/* Prime the queue */
Char = '\n';
Char1 = '\n';
Char2 = '\n';
Char3 = '\n';
new_char(); /* Fill Char, Char1, Char2 and Char3 */
while (Char != EOF) /* All of the words in the file */
{
if (isdigit(Char))
have_number();
else
if (isalpha(Char) || Char == '\'')
have_letter();
else
if (Char == '$' && isdigit(Char1))
have_dollars();
else
have_special();
}
}
void have_dollars(void)
{
long int value;
value = 0L;
for (new_char() ; isdigit(Char) || Char == ',' ; new_char())
{
if (Char != ',')
value = 10 * value + (Char-'0');
}
say_cardinal(value); /* Say number of whole dollars */
/* Found a character that is a non-digit and non-comma */
/* Check for no decimal or no cents digits */
if (Char != '.' || !isdigit(Char1))
{
if (value == 1L)
outstring("dAAlER ");
else
outstring("dAAlAArz ");
return;
}
/* We have '.' followed by a digit */
new_char(); /* Skip the period */
/* If it is ".dd " say as " DOLLARS AND n CENTS " */
if (isdigit(Char1) && !isdigit(Char2))
{
if (value == 1L)
outstring("dAAlER ");
else
outstring("dAAlAArz ");
if (Char == '0' && Char1 == '0')
{
new_char(); /* Skip tens digit */
new_char(); /* Skip units digit */
return;
}
outstring("AAnd ");
value = (Char-'0')*10 + Char1-'0';
say_cardinal(value);
if (value == 1L)
outstring("sEHnt ");
else
outstring("sEHnts ");
new_char(); /* Used Char (tens digit) */
new_char(); /* Used Char1 (units digit) */
return;
}
/* Otherwise say as "n POINT ddd DOLLARS " */
outstring("pOYnt ");
for ( ; isdigit(Char) ; new_char())
{
say_ascii(Char);
}
outstring("dAAlAArz ");
return;
}
void have_special(void )
{
if (Char == '\n')
outchar('\n');
else
if (!isspace(Char))
say_ascii(Char);
new_char();
return;
}
void have_number(void)
{
long int value;
int lastdigit;
value = Char - '0';
lastdigit = Char;
for (new_char() ; isdigit(Char) ; new_char())
{
value = 10 * value + (Char-'0');
lastdigit = Char;
}
/* Recognize ordinals based on last digit of number */
switch (lastdigit)
{
case '1': /* ST */
if (makeupper(Char) == 'S' && makeupper(Char1) == 'T' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '2': /* ND */
if (makeupper(Char) == 'N' && makeupper(Char1) == 'D' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '3': /* RD */
if (makeupper(Char) == 'R' && makeupper(Char1) == 'D' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '0': /* TH */
case '4': /* TH */
case '5': /* TH */
case '6': /* TH */
case '7': /* TH */
case '8': /* TH */
case '9': /* TH */
if (makeupper(Char) == 'T' && makeupper(Char1) == 'H' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
}
say_cardinal(value);
/* Recognize decimal points */
if (Char == '.' && isdigit(Char1))
{
outstring("pOYnt ");
for (new_char() ; isdigit(Char) ; new_char())
{
say_ascii(Char);
}
}
/* Spell out trailing abbreviations */
if (isalpha(Char))
{
while (isalpha(Char))
{
say_ascii(Char);
new_char();
}
}
return;
}
void have_letter(void)
{
char buff[MAX_LENGTH];
int count;
count = 0;
buff[count++] = ' '; /* Required initial blank */
buff[count++] = makeupper(Char);
for (new_char() ; isalpha(Char) || Char == '\'' ; new_char())
{
buff[count++] = makeupper(Char);
if (count > MAX_LENGTH-2)
{
buff[count++] = ' ';
buff[count++] = '\0';
xlate_word(buff);
count = 1;
}
}
buff[count++] = ' '; /* Required terminating blank */
buff[count++] = '\0';
/* Check for AAANNN type abbreviations */
if (isdigit(Char))
{
spell_word(buff);
return;
}
else
if (strlen(buff) == 3) /* one character, two spaces */
say_ascii(buff[1]);
else
if (Char == '.') /* Possible abbreviation */
abbrev(buff);
else
xlate_word(buff);
if (Char == '-' && isalpha(Char1))
new_char(); /* Skip hyphens */
}
/* Handle abbreviations. Text in buff was followed by '.' */
void abbrev(char buff[])
{
if (strcmp(buff, " DR ") == 0)
{
xlate_word(" DOCTOR ");
new_char();
}
else
if (strcmp(buff, " MR ") == 0)
{
xlate_word(" MISTER ");
new_char();
}
else
if (strcmp(buff, " MRS ") == 0)
{
xlate_word(" MISSUS ");
new_char();
}
else
if (strcmp(buff, " PHD ") == 0)
{
spell_word(" PHD ");
new_char();
}
else
xlate_word(buff);
}
static ULTRA_CFG config;
/* load phoneme sounds into gravis board */
static void load_phonemes(void)
{
int i = 0;
long silence;
int j = 0;
int ndx;
FILE *fp;
char name[80];
long size;
int *buf;
int *p;
int len;
unsigned char tmp1=0;
unsigned char tmp2=0;
UltraGetCfg(&config);
if (UltraOpen(&config,14) != ULTRA_OK) {
no_ultra = 1;
printf("\nNo Ultrasound card found. Sound will not be used");
return;
}
/* Reset ultrasound */
UltraReset(14);
UltraDisableOutput();
UltraSetLinearVolume(1,510);
UltraSetBalance(1, 7);
/* send a zero sample to the gus so that unused voices can use it */
UltraMemAlloc(2, &silence);
UltraDownload(&j, 0x40, silence, 2, 1);
/* set all voices to silence area of storage */
for (i = 0 ; i < 14; i++)
UltraSetVoice(i, silence);
UltraEnableOutput();
UltraSetFrequency(1, 9000L);
UltraMemInit();
printf("\nLoading ultrasound...\n");
for (ndx = 0; ndx < sizeof(phoneme_name)/sizeof(char *); ndx++) {
strcpy(name, phoneme_name[ndx]);
strcat(name, ".sam");
if ((fp = fopen(name, "rb")) == NULL) {
printf("\ncan't open phoneme file %s",name);
continue;
}
/* find each file and its size*/
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf = (int *)malloc(size);
if (buf == NULL) {
printf("\nCan't malloc buffer for %s file",name);
return;
}
for (p = buf, i = 0; i < size; i += 2, p++) {
fread(p, 2,1 ,fp);
}
/* allocate gus space for phoneme */
i = UltraMemAlloc(size, &p_tab[ndx].start);
p_tab[ndx].end = p_tab[ndx].start + size;
if (i == NO_MEMORY) {
printf("\nGus out of memory for phoneme storage at %s", name);
}
else {
UltraDownload(buf, 0x40, p_tab[ndx].start, size, 1);
}
fclose(fp);
free(buf);
}
if (debug ) {
for (i = 0; i < sizeof(phoneme_name)/sizeof(char *); i++) {
printf("\n%s", phoneme_name[i]);
UltraStartVoice(1, p_tab[i].start, p_tab[i].start, p_tab[i].end,
4);
while(!UltraVoiceStopped(1));
delay(300);
}
printf("\n");
}
}